import Glibc

class Timer {
    private let CLOCK_REALTIME = 0
    private var start_timespec = timespec()
    private var end_timespec = timespec()
    private var time_spec = timespec()
    func start() {
        clock_gettime(Int32(CLOCK_REALTIME),&start_timespec)
    }
    
    func stop() -> Double {
        clock_gettime(Int32(CLOCK_REALTIME),&end_timespec)
        let start_time = Double(start_timespec.tv_sec * 1_000_000 + start_timespec.tv_nsec / 1_000)
        let end_time = Double(end_timespec.tv_sec * 1_000_000 + end_timespec.tv_nsec / 1_000)
        let time = end_time - start_time
        return time / 1_000
    }
    func getTime() -> Double {
        clock_gettime(Int32(CLOCK_REALTIME),&time_spec)
        return Double(time_spec.tv_sec * 1_000_000 + time_spec.tv_nsec / 1_000)
    }
}

let timer = Timer()

var input:Double = 3000000

func GenerateFloatInput() -> [Double] {
    return [1.0, 2.0]
}

func GenerateBitOpsInput() -> [Int] {
    return [2, 3]
}

func GenerateIntegerInput() -> [Int] {
    return [2, 4]
}

func GenerateFakeRandomInteger() -> [Int] {
    let resource: [Int] = [12, 43, 56, 76, 89, 54, 45, 32, 35, 47, 46, 44, 21, 37, 84];
    return resource;
}

func GenerateFakeRandomFloat() -> [Double] {
    let resource: [Double] = [12.2, 43.5, 56.2, 76.6, 89.7, 54.9, 45.2, 32.5, 35.6, 47.2, 46.6, 44.3, 21.2, 37.6, 84.57]
    return resource;
}


// 浮点计算
func floatNumAddition(_ input: Double = input) -> Double {
    let count = 3000000
    let floatInputs = GenerateFloatInput()
    let f1 = 1.0 // floatInputs[0]
    let f2 = 2.0 // floatInputs[1]
    var f3 = 1.0
    let resources = GenerateFakeRandomInteger()
    timer.start()
    let resourcesLength = resources.count
    for i in 0..<count {
		if ((resources[i % Int(f3) & (resourcesLength - 1)] & 1) == 0) { // 335ms
			f3 += f1;
		} else {
			f3 += f2;
        }
    }
    let time = timer.stop()
    print(f3)
    print("Numerical Calculation - FloatNumAddition:\t"+String(time)+"\tms");
    return time
}

func floatNumSubtraction(_ input: Double = input) -> Double {
    let count = 3000000
    let floatInputs = GenerateFloatInput();
    let f1 = 1.0 // floatInputs[0];
    let f2 = 2.0 // floatInputs[1];
    var f3 = 13000000.0
    let resources = GenerateFakeRandomInteger()
    timer.start()
    let resourcesLength = resources.count
    for i in 0..<count {
        if ((resources[i % Int(f3) & (resourcesLength - 1)] & 1) == 0) {
			f3 -= f1
		} else {
			f3 -= f2
        }
    }
    let time = timer.stop()
    print(f3)
    print("Numerical Calculation - FloatNumSubstraction:\t"+String(time)+"\tms");
    return time
}

func floatNumProduction(_ input: Double = input) -> Double {
    let count = 3000000
    let floatInputs = GenerateFloatInput()
    let f1 = 1.0 // floatInputs[0]
    let f2 = 2.0 // floatInputs[1]
    var f3 = 1.0
    let resources = GenerateFakeRandomInteger()
    timer.start()
    let resourcesLength = resources.count
    for i in 0..<count {
        if ((resources[i & (resourcesLength - 1)] & 1) == 0) {
            f3 += f3 * f1
        } else {
            f3 += f3 * f2
        }
    }
    let time = timer.stop()
    print(f3)
    print("Numerical Calculation - FloatNumProduction:\t"+String(time)+"\tms");
    return time
}

func floatNumDivision(_ input: Double = input) -> Double {
    let count = 3000000
    var f3 = 1.0
    let resources = GenerateFakeRandomInteger()
    let inputs = GenerateFakeRandomFloat();
    timer.start()
    let resourcesLength = resources.count
    let inputsLength = inputs.count
    for i in 0..<count {
        if ((resources[i & (resourcesLength - 1)] & 1) == 0) {
            f3 += f3 / inputs[i & (inputsLength - 1)] / 0.1
        } else {
            f3 += f3 / inputs[(i + resources[i & (resourcesLength - 1)]) & (inputsLength - 1)] / 0.1
        }
    }
    let time = timer.stop()
    print(f3)
    print("Numerical Calculation - FloatNumDivision:\t"+String(time)+"\tms");
    return time
}

// 位运算
func bitOpsAND(_ input: Double = input) -> Double {    
    let count = 30000000
    let bitInputs = GenerateBitOpsInput()
    let b1 = 2 // bitInputs[0] // 10
    let b2 = 3 // bitInputs[1] // 11
    var b3 = 1
    let resources = GenerateFakeRandomInteger()
    timer.start()
    let resourcesLength = resources.count
    for i in 0..<count {
        if ((resources[i % b3 & (resourcesLength - 1)] & 1) == 0) {
            b3 = (b3 & b1) + 1
		} else {
            b3 = (b3 & b2) + 1
        }
    }
    let time = timer.stop()
    print(b3)
    print("Numerical Calculation - BitOpsAND:\t"+String(time)+"\tms");
    return time
}

func bitOpsOR(_ input: Double = input) -> Double {    
    let count = 30000000
    let b1 = 2 // bitInputs[0] // 10
    let b2 = 3 // bitInputs[1] // 11
    var b3 = 1
    let resources = GenerateFakeRandomInteger()
    timer.start()
    let resourcesLength = resources.count
    for i in 0..<count {
        if ((resources[i % b3 & (resourcesLength - 1)] & 1) == 0) {
            b3 = (b3 | b1) + 1
            // b3 = b3 | resources[i & (resourcesLength - 1)]
        } else {
            b3 = (b3 | b2) + 1
            // b3 = b3 | resources[(i + 5) & (resourcesLength - 1)]
        }
    }
    let time = timer.stop()
    print(b3)
    print("Numerical Calculation - BitOpsOR:\t"+String(time)+"\tms");
    return time
}

func bitOpsXOR(_ input: Double = input) -> Double {    
    let count = 30000000
    var b3 = 1
    let resources = GenerateFakeRandomInteger()
    timer.start()
    let resourcesLength = resources.count
    for i in 0..<count {
        if (b3 <= 0) {
            b3 = 1
        }
        if ((resources[i % b3 & (resourcesLength - 1)] & 1) == 0) {
            b3 = b3 ^ resources[i & (resourcesLength - 1)]
        } else {
            b3 = b3 ^ resources[(i + 5) & (resourcesLength - 1)]
        }
    }
    let time = timer.stop()
    print(b3)
    print("Numerical Calculation - BitOpsXOR:\t"+String(time)+"\tms");
    return time
}

func bitOpsNOT(_ input: Double = input) -> Double {   
    let count = 30000000
    let b1 = -2
    let b2 = -3
    var b3 = 1
    let resources = GenerateFakeRandomInteger()
    timer.start()
    let resourcesLength = resources.count
    for i in 0..<count {
        if ((resources[i % b3 & (resourcesLength - 1)] & 1) == 0) {
            b3 += ~b1
        } else {
            b3 += ~b2
        }
    }
    let time = timer.stop()
    print(b3)
    print("Numerical Calculation - BitOpsNOT:\t"+String(time)+"\tms");
    return time
}

func bitOpsShiftLeft(_ input: Double = input) -> Double {    
    let count = 30000000
    let bitInputs = GenerateBitOpsInput()
    let b1 = 2// bitInputs[0] // 10
    var b3 = 1
    let resources = GenerateFakeRandomInteger()
    timer.start()
    let resourcesLength = resources.count
    for i in 0..<count {
        if ((resources[i % b3 & (resourcesLength - 1)] & 1) == 0) {
            b3 += b1 << 1;
        } else {
            b3 += b1 << 2;
        }
    }
    let time = timer.stop()
    print(b3)
    print("Numerical Calculation - BitOpsShiftLeft:\t"+String(time)+"\tms");
    return time
}

func bitOpsShiftRight(_ input: Double = input) -> Double {  
    let count = 30000000
    let bitInputs = GenerateBitOpsInput()
    let b1 = 2 // bitInputs[0] // 10
    var b3 = 1
    let resources = GenerateFakeRandomInteger()
    timer.start()
    let resourcesLength = resources.count
    for i in 0..<count {
        if ((resources[i % b3 & (resourcesLength - 1)] & 1) == 0) {
            b3 += b1 >> 1
        } else {
            b3 += b1 >> 2
        }
    }
    let time = timer.stop()
    print(b3)
    print("Numerical Calculation - BitOpsShiftRight:\t"+String(time)+"\tms");
    return time
}

// 整数计算
func integerNumAddition(_ input: Double = input) -> Double {    
    let count = 30000000
    let IntegerInputs = GenerateIntegerInput()
    let resources = GenerateFakeRandomInteger()
    let i1 = 2 // IntegerInputs[0]
    let i2 = 4 // IntegerInputs[1]
    var i3 = resources[0];
    timer.start()
    let resourcesLength = resources.count
    for i in 0..<count {
        if ((resources[i % i3 & (resourcesLength - 1)] & 1) == 0) { // 1.07ms 
            i3 += i1
        } else {
            i3 += i2
        }
    }
    let time = timer.stop()
    print(i3)
    print("Numerical Calculation - IntegerNumAddition:\t"+String(time)+"\tms");
    return time
}

func integerNumSubstraction(_ input: Double = input) -> Double {   
    let count = 30000000
    let IntegerInputs = GenerateIntegerInput()
    let i1 = 2 // IntegerInputs[0]
    let i2 = 4 // IntegerInputs[1]
    var i3 = 130000000
    let resources = GenerateFakeRandomInteger()
    timer.start()
    let resourcesLength = resources.count
    for i in 0..<count {
        if ((resources[i % i3 & (resourcesLength - 1)] & 1) == 0) { // 1.07ms 
			i3 -= i1
		} else {
			i3 -= i2
		}
    }
    let time = timer.stop()
    print(i3)
    print("Numerical Calculation - IntegerNumSubstraction:\t"+String(time)+"\tms");
    return time
}

func integerNumProduction(_ input: Double = input) -> Double {     
    let count = 30000000
    var i3 = 1
    let resources = GenerateFakeRandomInteger()
    timer.start()
    let resourcesLength = resources.count - 1
    for i in 0..<count {
        if ((resources[i % i3 & resourcesLength] & 1) == 0) { // ark:21ms node:4ms
			i3 *= 3 // resources[i & resourcesLength]
		} else {
			i3 *= 2 // resources[(i + 5) & resourcesLength]
		}
        if (i3 > 10000000) {
            i3 = 1
        }
    }
    let time = timer.stop()
    print(i3)
    print("Numerical Calculation - IntegerNumProduction:\t"+String(time)+"\tms");
    return time
}

func integerNumDivision(_ input: Double = input) -> Double {   
    let count = 30000000
    let IntegerInputs = GenerateIntegerInput()
    let i1 = 2 // IntegerInputs[0]
    let i2 = 4 // IntegerInputs[1]
    var i3 = 32768
    let resources = GenerateFakeRandomInteger()
    var results = [0, 0, 0, 0, 0]
    timer.start()
    let resourcesLength = resources.count
    for i in 0..<count {
        if (i3 <= 4) {
            i3 = 32768;
        }
        if ((resources[i % i3 & (resourcesLength - 1)] & 1) == 0) { // ark:21ms node:4ms
            // i3 += i2 / i1
            i3 /= i1
            /* results[i % 5] = i2 / i1 */
        } else {
            // i3 += i2 / i1 / 2
            i3 /= i2
            /* results[i % 5] = i2 / i1 / 2 */
        }
    }
    let time = timer.stop()
    /* for i in 0..<5 { */
        /* i3 += results[i] */
    /* } */
    print(i3)
    print("Numerical Calculation - IntegerNumDivision:\t"+String(time)+"\tms");
    return time
}

// 浮点数比较
func floatNumComparision(_ input: Double = input) -> Double {    
    let count = 3000000
    let resources = GenerateFakeRandomFloat()
    let IntegerInputs = GenerateIntegerInput()
    var res = 1
    timer.start()
    let resourcesLength = resources.count
    for i in 0..<count {
        let next_index = i + 5
        let next_res = res + 1
        if (resources[i % res & (resourcesLength - 1)] > resources[next_index % next_res & (resourcesLength - 1)]) {
            res += 1
        } else {
            res += 2
        }
    }
    let time = timer.stop()
    print(res)
    print("Numerical Calculation - FloatNumComparision:\t"+String(time)+"\tms");
    return time
}

// String运算
func stringCalculation(_ input: Double = input) -> Double {
    let count = 3000000 / 1000
    let str1 = "h"
    var res = "11"
    let resources = GenerateFakeRandomInteger()
    timer.start()
    for i in 0..<count {
        if (resources[i % res.count % 15] > resources[(i + resources[i % 15]) % res.count % 15]) {
            res += str1 + String(i);
        } else {
            res += str1;
        }
    }
    let time = timer.stop()
    print(res.count)
    print("Numerical Calculation - StringCalculation:\t"+String(time)+"\tms");
    return time
}

func runFloatNumAddition()->Double{
    return floatNumAddition(input)
}
func runFloatNumSubtraction()->Double{
    return floatNumSubtraction(input)
}
func runFloatNumProduction()->Double{
    return floatNumProduction(input)
}
func runFloatNumDivision()->Double{
    return floatNumDivision(input)
}
func runBitOpsAND()->Double{
    return bitOpsAND(input)
}
func runBitOpsOR()->Double{
    return bitOpsOR(input)
}
func runBitOpsXOR()->Double{
    return bitOpsXOR(input)
}
func runBitOpsNOT()->Double{
    return bitOpsNOT(input)
}
func runBitOpsShiftLeft()->Double{
    return bitOpsShiftLeft(input)
}
func runBitOpsShiftRight()->Double{
    return bitOpsShiftRight(input)
}
func runIntegerNumAddition()->Double{
    return integerNumAddition(input)
}
func runIntegerNumSubstraction()->Double{
    return integerNumSubstraction(input)
}
func runIntegerNumProduction()->Double{
    return integerNumProduction(input)
}
func runIntegerNumDivision()->Double{
    return integerNumDivision(input)
}
func runFloatNumComparision()->Double{
    return floatNumComparision(input)
}
func runStringCalculation()->Double{
    return stringCalculation(input)
}

_ = runFloatNumAddition()
_ = runFloatNumSubtraction()
_ = runFloatNumProduction()
_ = runFloatNumDivision()
_ = runBitOpsAND()
_ = runBitOpsOR()
_ = runBitOpsXOR()
_ = runBitOpsNOT()
_ = runBitOpsShiftLeft()
_ = runBitOpsShiftRight()
_ = runIntegerNumAddition()
_ = runIntegerNumSubstraction()
_ = runIntegerNumProduction()
_ = runIntegerNumDivision()
_ = runFloatNumComparision()
_ = runStringCalculation()
